import java.util.concurrent.ScheduledExecutorService;

/**
 * 描述:分布式，微服务
 *  1.CAP
 *      1.C：一致性，所有节点在同一时间的数据要完全一致，强一致性
 *      2.A：可用性：服务一直可用，不出现用户操作失败或者超时等影响用户体验的情况
 *      3.P：分区容错性：分布式系统遇到某个节点或网络分区故障的时候，仍然能够对外提供满足一致性和可用性的服务
 *      4.CP和AP：分区容错是必须保证的，当发生网络分区时，要继续服务，那么强一致性和可用性只能二选一
 *  2.BASE：即使无法做到强一致性，但每个应用可以根据自身业务特点，采取适当的方式实现弱一致性
 *      1.BA：基本可用：响应时间上的损失或者系统功能上的损失
 *      2.S：软状态：数据同步允许一定的延迟
 *      3.E：最终一致性：系统中的数据副本，经过一段时间，最终能达到一致性
 *  3.负载均衡算法、类型
 *      1.随机
 *      2.轮询
 *      3.加权轮询
 *      4.最小连接数（最小访问量）
 *      5.源地址哈希
 *      6.加权随机
 *  4.分布式架构下session共享有什么方案：
 *      1.redis存储token
 *      2.服务器间session同步
 *      3.ip绑定策略，nginx中可以设置同一个ip只能在同一个机器访问，这样失去了负载均衡的意义
 *  5.分布式Id生成方案
 *      1.uuid:生成快，性能好，无序，长度长，字符串
 *      2.数据库自增id：依赖db，存在单点问题
 *      3.分布式数据库自增id：每次获取id都要请求一次数据库，而且维护困难
 *      4.leaf-segment：每次获取一个id段，比如1-100的id段，存到本地备用，只会请求一次数据库
 *      5.双buffer：将获取一个号段，变成获取两个号段，先获取了100个id，然后用到10%的时候，再异步获取一百个
 *      6.基于redis，mongo，zk等中间件
 *      7.雪花算法:64为的全局id，引入时间戳和保持自增
 *          1.最高位为符号位，位0
 *          2.41位的时间戳，精确到毫秒级
 *          3.10位机器标识，最多可支持到1024台机器
 *          4.12位的计数序列号，支持每毫秒4096个Id生成
 *      新版回答：
 *          1.四种分布式Id的策略，
 *              1.全局唯一，无需递增：一般用uuid来做
 *              2.全局唯一，趋势递增：比如1 2 3 8 9 5 6 等，一般的互联网分布式id只能满足这个
 *              3.全局唯一，单调递增：1 2 4 7 9 ，这种一般特点业务才能满足，比如微信的业务
 *              4.全局唯一，顺序递增：这种必须是一个数据库中的递增，不保证高可用，性能差，无法扩展
 *          2.雪花算法：
 *              1.实现方式：每台机器的时间戳 + 机器id + 顺序递增值，保证趋势递增
 *              2.优点：性能好，保证高可用，没有网络io消耗
 *              3.缺点：超大并发量下可能存在重复值，因为每毫秒最大的数值是4096
 *          3.利用db的自增主键
 *              1.实现方式：发号机器保证高可用，集群部署，主从复制，单个发号机器发的号是单调递增的，但是总的发号机器发的号是趋势递增的
 *              2.优点：保证高可用，一台发号机器挂了，还有其它的保证发号，不受限于本机的时钟
 *              3.缺点：受限于网络io，每次发号都得请求一次db
 *          4.发号机器，缓存本地号段
 *              1.实现方式：每台机器本地缓存一个号段，由发号机器发号，对db的访问量大幅度下降，所以不再需要db集群，而只需要单个db，每台机器从db中获取号段，
 *                缓存到本地，用完再取或者设置用到了%多少就去取。db只用存储已发出去的最大号段
 *              2.优点：对db的访问大幅下降
 *              3.缺点：如果单点故障，需要主从复制，保证强一致性
 *  6.分布式锁的解决方案
 *      1.zookeeper分布式锁
 *          1.zk通过临时节点，解决了死锁问题，因为节点挂掉，那么这个临时节点也会自动删除掉，客户端就能获取到锁
 *      2.redis分布式锁
 *          1.setnx，如果key不存在，则返回1并设置，存在则返回0
 *          2.设置超时时间，解决死锁问题
 *          4.加锁和设置锁的超时时间并不是原子操作，所以可能产生死锁，可以set命令
 *          5.高并发场景下，锁的超时时间设置可能产生问题，比如进程A加锁，但是还没释放锁就自动过期了，线程B恰好又进来加锁，结果A释放的是B的锁
 *            所以set的值最好为一个Uuid，释放的时候判断是否是这个uuid
 *          6.redission加锁，看门狗机制，自动刷新超时时间，lua原子操作，可重入性和锁续期
 *          7.redis分布式锁最大问题是集群模式下，master节点宕机，锁丢失
 *  7.分布式事务解决方案：
 *      1.两种分布式事务：
 *          1.在一个Method中操作了两种数据库，用@Trancational没有用，可以用JTA解决
 *          2.A节点调用B节点，A节点调用DBA，B节点调用DBB
 *      2.XA规范：分布式事务规范，定义了分布式事务模型
 *          1.四个角色：事务管理器（协调者TM）、资源管理器（参与者RM）、应用程序AP、通信资源管理器CRM
 *          2.全局事务：一个横跨多个数据库的事务，要么同时提交，要么同时回滚
 *      3.两阶段协议
 *          1.第一阶段：准备阶段，协调者向各个参与者发起询问，说要执行一个事务，，各个参与者回复YES,NO
 *          2.第二阶段：提交阶段，所有参与者都回复了YES，协调者向参与者发起COMMIT，参与者执行事务，发送ACK确认，若是有一个参与者回复NO或者超时，
 *            协调者向所有参与者发起事务回滚操作，所有参与者回滚，返回ACK
 *          3.问题
 *              1.单点故障：一旦事务管理器出现故障，整个系统不可用（参与者都会阻塞住），并且出现一系列问题
 *              2.阶段1需要等待，影响并发
 *          4.项目：这种方案比较适合用于单应用里面，比如一个方法调用了两个数据库，效率很低，不适合高并发，用spring + JTA就能实现，一般我们
 *              很少用，其实一个服务操作两个不同的库，是不合规的，微服务基本上要求一个服务只能操作一个库，然后想要用这个服务就通过rest或者rpc调用
 *      4.三阶段协议：主要解决两阶段的单点故障问题
 *          1.第一阶段：发送cancommit消息，确认数据库环境正常
 *          2.第二阶段：发送precommit消息，完成sql语句操作，但未提交事务
 *          3.第三阶段：发送docommit消息，完成事务的提交和回滚
 *          4.超时机制：如果precommit成功了，但一定时间内还未收到docommit消息，则认为协调者挂了，则自己会执行docommit操作
 *          4.项目：三阶段协议其实和两阶段差不多，只不过多了个确认数据库环境是否异常的阶段，并且增加了超时重试的机制，也不用
 *      5.TCC补偿事务（Try,Confirm,Cancel）
 *          1.try:做业务检查和资源预留
 *          2.confirm:做业务确认
 *          3.cancel:实现一个与try相反的回滚操作，是业务上的回滚，不是数据库的回滚，比如你try加了100元钱，那么这个回滚就需要减少100元钱
 *          4.TM首先发起所有分支的try操作，一旦有一个失败，TM会发起所有事务的cancel操作，全部成功，则发起confirm
 *          5.问题
 *              1.对业务侵入性很大
 *          6.项目：这个方式用的也比较小，一般先检查数据的条数或者关键数据，然后调用其他库的服务时，如果抛出异常，就硬编码去回滚，比如某个数量 + 1，
 *              那么出现问题就得手动调用减1的服务，代码量巨大，而且承受不住并发，难以维护
 *      6.最终一致性方案：消息队列实现
 *          1.本地消息表：字段有，id，业务id，消息状态，消息内容，重试次数等
 *              1.消息生产方，需要额外建一个消息表，并且记录消息的发送状态。消息表和业务数据要在一个库里面
 *              2.消息经过mq发送给消费方，发送失败则自动重试
 *              3.消息消费方处理这个消息，完成业务逻辑，然后将是否成功的消息通过mq发送给消息生产方
 *              4.生产方监听消费方是否消费成功，再修改本地消息表中的状态
 *              5.如果消息在mq中，或者网络中发送失败，则在保证接口幂等的情况下，引入一个定时任务，读取消息发送失败的状态
 *              6.本地消息表中失败的消息，就重新读取发送到mq中重试，直到重试次数阈值之前成功，若不成功，则短信告警，人工介入或者回滚
 *              7.缺点：与业务耦合，难以做通用性，高并发下有瓶颈
 *          2.非事务消息（kafka）：
 *              1.系统A增加一张消息表，不直接发送消息给B，而是把消息写入消息表，DB1扣钱操作和写入消息表保证原子性
 *              2.系统A有一个后台程序，不断把消息表中的消息传给中间件。如果发送超时，失败等问题就重试，保证信息不丢失但是可能会重复
 *              3.系统B消费消息解决两个问题：
 *                  1.丢失消费：假如消费了消息，但是突然宕机，所以要维护一个offset，在消息消费完再提交
 *                  2.重复消费：增加判重表，或者可以用业务id判重，实现业务幂等，DB2加钱操作和写判重表要在同一个数据库事务中完成
 *              4.缺陷：需要增加消息表，和后台任务，业务耦合严重
 *          3.事务消息（rocketMq）：
 *              1.rocketmq把消息的发送拆成两个阶段，prepare预发送和commit确认发送
 *              2.系统A调用prepare接口预发送消息，消息会存在中间件中，不会把消息给消费者消费
 *              3.系统A进行扣钱操作
 *              4.系统A调用confirm操作确认发送消息，此时消息中间件才会把消息发送给消费者
 *              5.需要解决两个问题：
 *                  1.步骤3超时或者失败：步骤4超时或者失败
 *                  2.rocketmq会定期（1m）扫描所有预发送倒是还没确认的消息，回调给发送方，询问是要发送还是取消。业务方根据业务判断
 *                  3.rocketmq和kafka的实现区别就是在于rocketmq有自动的定时扫描机制，其实本地消息表也未必不需要，消费方也是要解决重复消费问题
 *          4.面临一个问题：消费方消息消费失败怎么办？
 *              1.可以控制offset去重试，但是一直失败只能人工介入，因为要控制整个流程回滚代价巨大
 *      7.阿里开源的分布式事务解决方案seata
 *      8.强一致性与最终一致性
 *          1.强一致性指的是用户查询到的数据都是最近一次成功更新的数据，强一致性是高度的一致，是最难实现的，用的是2阶段或者3阶段的分布式事务
 *          2.最终一致性指的是允许当前用户查询到的数据不是最近一次更新的，但是在一定的时间内必须要能查询到最近更新的那次数据，用的是消息队列或者本地消息列表的分布式事务
 *      9.同步双写（多写） + 异步对账（适用于缓存，数据库，多数据库之间）
 *          1.其中一个数据库写成功了，另外的数据库或者缓存不管写没写成功，都给客户端返回成功
 *          2.后期再通过发送mq消息或者异步对账，全量对账，增量对账等
 *      10.总结：
 *          1.其实分布式事务就两种思维
 *              1.2PC：XA和TCC和AT，适用于并发不高，开发门槛低，并且可以保证回滚
 *              2.1PC：最终一致性，事务消息，异步对账，事务状态表和补偿机制，高并发，开发难度高，需维护，并且不能保证回滚
 *      11.案例
 *          1.数据分发案例（最终一致性案例）
 *              1.项目中经常存在类似需求，新增一条数据的时候，会存入mysql，并且会过滤一些关键索引字段再往es存储一份，最后往数仓存储一份
 *              2.通常的做法是先存mysql，然后发送一条mq，中间保证mysql事务，但是这样的话，有时候会出现说mq消息没有发送成功或者消费者消费mq消息的时候，
 *                出现消费失败的情况，这时候mysql数据已经存储进去了，但是es或者数仓中没有，出现了数据不一致的情况
 *              3。这种数据不一致的情况下，一般数据分发不保证强一致性，只需要保证最终一致性就行，所以我们通常的做法有两个
 *                  1.同步双写 + 异步对账：顾名思义，同步双写就是mysql和发送mq两个操作在同一个事物中，保证mysql的操作必定能成功，
 *                    然后消息发送，就尽最大可能保证成功（如何尽最大可能，后面讲），接着后台是有个定时任务，维护一个时间指针，
 *                    不断的去查询mysql新更新或者添加的数据，再跟es和数仓中的数据作比对，异步对账，对不上的人工报警，保证最终一致性
 *                  2.然后又出现一个问题，如何尽可能保证发送消息成功？两种方式
 *                      1.本地消息表，如果是rocketmq的话，其实不需要本地消息表，它可以预发送消息，然后对发送失败的可以用定时任务去自动去重试，继续发送，
 *                        这叫做事物消息。但是我们一般用Kafka是没有超时重试的，所以用本地消息表，存储kafka发送消息，返回ack失败或者超时的，定时开启任务进行重试。
 *                        这种方式代码耦合性太高，其实不推荐使用
 *                      2.CDC，变更数据捕获机制，可以用阿里巴巴的canal，去捕捉数据库binlog的消息，并且自动发送到kafka，中间由组件保证消息发送的事务，
 *                        这样保证了mysql存储数据到消息发送到kafka的原子性。但是这种可能出现说消息的重复发送，记得要保证幂等。同样，
 *                        这样的方式引入中间件，会导致系统复杂度变高，而且要保证canal的高可用
 *   8.接口幂等性
 *      1.根据具体业务来判断怎么处理
 *          1.token + redis 机制(举例订单支付业务)
 *              1.当到了支付的场景时，生成一个全局唯一的token，存入到redis中，并且返回给客户端
 *              2.发起支付操作的时候附带这个token
 *              3.接口处理：
 *                  1.获取分布式锁（处理并发情况）
 *                  2.判断redis中是否存在token
 *                  3.存在，执行支付业务逻辑，执行后删除token，否则返回订单已支付
 *                  4.释放分布式锁
 *          2.CAS保证接口幂等
 *              1.状态机制幂等（举例订单支付状态 0 待支付 1 支付中）
 *              2.update order set status = 1 where status = 0 and orderId = ?
 *              3.要进行支付，上来先更新一下订单的支付状态
 *          3.乐观锁方案，版本控制
 *              1.大部分订单系统都是分布式部署的，订单和库存业务独立部署，由于网络原因，可能请求延迟了，重新发起请求，就可能导致幂等性问题
 *              2.update t_goods set count = count - 1 where good_id = 2
 *              3.如果请求两次，没保证幂等，则库存减了两个
 *              4.借鉴数据库乐观锁或者版本控制：update t_goods set count = count - 1,version = version + 1 where good_id = 2 and version = 1
 *          4.防重表
 *              1.数据库建立防重表，加唯一索引，订单有状态控制，则可以支付成功后删除订单号，没有的话也可以不删除
 *   9.高并发预约系统设计：疫情期间，政府免费发放口罩的预约服务，服务升级
 *      1.旧版
 *          1.硬件参数：
 *              1.一台16核，64g内存的服务器
 *              2.mysql服务器，单台
 *          2.产生问题：
 *              1.系统qps四五百多
 *              2.预约页面在高峰时期页面加载卡顿，url访问缓慢，系统崩溃掉 （解决方法7，5）
 *              3.netstat 查看当前80端口连接数  netstat -ant|awk '/^tcp/ {++S[$NF]} END {for(a in S) print (a,S[a])}' （解决方法8）
 *                  1.状态是established的连接数量为500多
 *                  2.状态是time_wait的连接数量为？？？(这个值需要深思熟虑一下)
 *                      1.TIME_WAIT出现的原因是客户端请求到linux，会占用一个端口。如果请求了，服务端没返回数据，就回出现TIME_WAIT
 *              4.服务中调用了三个接口，并且都是顺序执行的，比如身份信息校验接口，失信人接口之类的，必须获取到数据之后才能进行下一步操作
 *                  三个接口的调用大概花费2-3s，原因是网络环境复杂，接口数据需要经过两三家公司的层层封装调用返回（解决方法9）
 *              5.会有人在预约开始之前一分钟就不断地对服务发起请求，有点像黄牛用代码写的程序，毕竟当时疫情刚开始，口罩是很值钱的（解决方法3）
 *              6.没有采用缓存，已经预约的人还能再次请求，查询数据库之后才返回（解决方法5.4）
 *              7.oracle的连接数有到了800多，查询变得缓慢，有些日志中报超时错误(解决方法2)
 *              8.出现超约现象，原本是定只能约500人，但是多约了3个（解决方法5.5）
 *              9.页面的所有资源加起来大小有3m，还有两张300k的图片，每次加载页面需要大约4m的带宽（解决方法7）
 *              10.记录预约成功或者失败的日志到oracle中，产生压力（解决方法5.3）
 *              11.预约的时候从预约，到预约成功，中间经过了5s左右(解决方法5.6，5.7)
 *          3.当时的解决方案：
 *              1.软件方面
 *                  1.采用redis做缓存
 *                  2.建立数据库主从复制，读写分离
 *                  3.nginx配置对某个ip请求频率高的或者请求次数多的拦截
 *                  4.已预约的手机号码防止再次进行预约，将预约时段和手机号码作为Key，存入redis
 *                  5.预约主要业务逻辑
 *                      1.缓存预热，页面上需要展示的一些通过接口获取的数据，库存预热，预约的时段和数量存入redis
 *                      2.mq异步，削峰，预约成功则扣减redis数量，redis新增一条预约的人员的Key，值为1（预约状态，0表示预约失败，1表示正在预约中，2表示预约成功），
 *                          值大于1就拦截，防止重复预约，然后发送一mq消息到业务处理逻辑
 *                      3.日志消息发送到mq中收集
 *                      4.mq处理成功，则redis的预约人员的key设置为2，处理失败，则预约状态变为0，redis库存+1
 *                      5.整个预约的主要逻辑加上redision分布式锁，锁的是预约时间段，并且设置超时时间
 *                      6.返回一个正在预约中的状态给前端，前端每隔1s发起一个短轮询，ajax请求，获取是否预约成功，获取到的值为0则表示失败，数据库查询失败原因返回
 *                      7.是否预约成功的逻辑是直接查询redis的时间段和手机号的key，成功则返回，查询不到则重试5次自动失败
 *                  6.nginx作负载均衡，部署三台服务，分散系统压力
 *                  7.nginx反向代理前端代码，开启gzip压缩技术，静态资源缓存
 *                  8.解决tcp连接time_wait问题
 *                      1.linux可以tcp端口数开放到65535个
 *                      2.linux可以开启端口快速重用
 *                  9.新增全局线程池，设置核心40线程，最大线程 2 * 核心线程，多线程同时获取3个接口数据，CountDownLatch控制返回
 *              2.硬件方面
 *                  1.mysql主从集群，分散读并发压力
 *                  2.增加两台 16核，64g内存的服务器
 *          4.优化后的系统
 *              1.QPS:5000多
 *          5.现在的解决方案（目的是解决更大的并发与流量，基于以上的解决方案新增以下几点）：
 *              1.引入Springcloud Gateway 网关服务统一鉴权与服务间负载均衡
 *              2.引入Springcloud Alibaba Sentinal，作服务间的限流与熔断，降级，隔离，保证高可用与集群的正常运行
 *              3.redis作redis-cluster集群，主从模式，保证数据的高可用性，独写分离，解决内存瓶颈
 *      2.新版（需要解决的问题）
 *          1.如何解决超约问题
 *              1.incryby的操作是原子性的，将incryby减库存的操作和判断库存当前数量的操作，写到一个lua脚本中，用redis执行，是一种阻塞的情况
 *              2.用redission做分布式锁，本质上也是用lua脚本来加锁，尝试获取锁，获取不到返回服务器正忙，请重试，是一种类似CAS的情况，性能更好点
 *                  1.分布式锁问题：主从节点，如果主宕机，切换到从，会导致部分锁的丢失（无法解决）
 *                  2.释放锁之前宕机，永远释放不了锁（加超时时间）
 *                  3.业务还没执行完，锁已经因为超时时间释放了，执行了释放锁把其它线程的释放了（锁的值加uuid）
 *              3.数据库用CAS，update table set a = a - 1,version = version + 1 where version <= 100，压力打在数据库上，不合理
 *          2.如何限流
 *              1.微服务接口层面限流：hystrix和sentinel，或者gruva的RateLimiter结合AOP做注解配置
 *              2.防刷：黑名单控制；nginx限制每个ip请求接口的频率
 *              3.用户预约判重：每个用户只能预约一次
 *              4.前端：库存抢光后，按钮置灰，禁止多余请求进来
 *          3.如何快速返回预约结果（要求在1s内返回有效响应，3秒内返回结果）
 *              1.业务操作：发起预约，判断登录信息，校验数据合法性，判断是否重复预约，调用三个接口（每个接口平均1s）,通过接口数据身份认证与预约资格确认，
 *                  查询预约库存，存入预约数据，保存操作日志，返回预约结果
 *              2.业务瓶颈：
 *                  1.三个接口的调用：通过设置全局线程池，多线程同时处理三个接口，用countDownLatch控制接口返回数据，时间缩短为1s
 *                  2.查询预约库存，存入预约数据不是原子性的，会出现超约的情况，加锁解决，但是系统阻塞并发不够
 *                  3.压测下，数据库操作会产生少部分请求超时现象，请求响应速度变慢，数据库服务器CPU飙高，连接数正常，建议了运维搞主从和读写分离
 *              3.异步预约
 *                  1.引入redis库存预热，将预约数量存入redis，用incryby来扣减，扣减成功发送mq预约数据，返回排队中，请稍后
 *                  2.mq异步处理，保证幂等，成功将key存入redis，用websocket返回给前端一个成功的消息或者前端短轮询预约是否成功，每隔2s，五次失败
 *                  3.日志直接发送到mq中，在慢慢落入到数据库中
 *          4.如何提高并发
 *              1.加机器，三台，Nginx做负载均衡
 *              2.数据库主从，读写分离
 *   10.分布式系统设计
 *      1.查看 分布式系统设计的doc文档
 *   11.如何保证缓存与数据库的一致性
 *      1.先更新数据库，再更新缓存
 *          1.线程A更新了数据库，线程B也更新了数据库，线程B更新了缓存，线程A再更新了缓存，结果缓存是错的，出现脏数据
 *          2.如果是一个写操作比较频繁的场景，那么读不多的话，就频繁更新，浪费性能，而且如果缓存计算的逻辑比较复杂，更加浪费性能
 *      2.先删缓存，再更新数据库
 *          1.请求A写操作，删除缓存，请求B发现缓存不在，查询数据库得到旧的值，更新了缓存，请求A再成功更新数据库，就会出现不一致的情况
 *          2.而且不给缓存设置过期时间的话，该数据就永远是脏数据
 *          2.解决：延迟双删策略：先删缓存，再修改数据库，休眠1s，再异步删除缓存，可以将1s以内的缓存脏数据删除
 *      3.先修改数据库，再删除缓存
 *          1.缓存刚好失效，请求A查询数据库得到旧值，请求B将新值写入数据库，请求B删除缓存，请求A将查到的旧值写入缓存
 *          2.请求B将值写入数据库的时间肯定是比请求A查询旧值慢的，然后A查完旧值再立马写入缓存应该是很快的步骤，B最后删除缓存应该是很慢的，所以这种情况很少见
 *          3.解决办法：更新数据库数据，缓存删除失败，则把Key发送给消息队列，利用消息队列的重试机制去不断删除
 *              1.延迟双删可以使用ScheduledExecutorService，全局定义延迟线程池，再进行一次删除
 *              2.想要多次尝试，可以使用delayQueue队列，添加不同等待时长的任务
 *          4.订阅mysql的binLog日志，取出修改数据的key，然后尝试删除，失败则发送到消息队列重试
 *              1.用canal 获取 mysql binlog日志，发送到kafka中，监测UPDATE,INSERT,DELETE类型的语句，做出判断是否要更新缓存，做统一处理
 *              2.获取binglog的方式是类似mysql的主从同步，将canal伪装成一个slave节点
 *   12.eureka,zookeeper,nacos的区别
 *      1.简述一下CAP的原理
 *      2.为什么CAP只能保证两个
 *          1.因为C如果是第一需求，则一定会影响A的功能，因为数据传输是有延迟的，可用性就会降低
 *          2.如果A是第一需求，那么C不能保证，因为数据一致性的过程没那么快
 *          3.而要同时满足可用性和一致性，分区容错性就很难保证了，因为可能出现单点故障导致数据不一致或者请求无响应
 *      3.zookeeper保证了CP，因为master节点挂了就会进行选择，但是当达到半数以上的slave节点都挂了，就瘫痪了，不保证可用；而eureka的集群方式跟zookeeper不一样，
 *        它保证只要有一台eureka节点在，就能提供服务，但是不能提供所有的服务，可能A请求查得到，B请求就查不到，所以是AP的。nacos是CP+AP的，不仅支持服务注册与发现，
 *        还支持配置中心
 *   13.集群脑裂：
 *      1.因为网络超时等原因，导致master节点与slave节点之间无法通信，所以系统开始选举另一个master节点。等选举完发现旧的master节点又因为网络好了而能连的上了，
 *        就出现两个master节点，客户端连的是不同的master，就出现了脑裂
 *      2.解决方式：
 *          1.隔离：对旧的Master进行隔离，杀死服务或者不提供服务，具体的隔离技术，不同系统不一样
 *          2.每次新的master上位，旧的master会自动退位
 *          3.租约机制：租约是一个定了有效期的契约，由master和协调器签订的，租约到期之后，要么续约要么过期；新的master上位时，旧的一定会失效
 *      3.举例：
 *          1.mysql的高可用架构MHA，为每台机器都装上一个Agent，一个独立的进程，会监听master或者slave是否宕机
 *          2.agent将自己的监听信息上报给MHA Manager，由manager决定是否发生高可用切换
 *          3.解决脑裂问题的方式是：新的master上位前会对旧的master进行隔离操作，通过ssh登录旧的master，执行shutdown脚本对旧的master进行强杀
 * @author
 * @created 2022/2/7 17:10
 */
public class Cloud {

}
